/*
 * AnnotationHelper.java
 *
 * Created on 30 March 2007, 08:24
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package net.siit.ke;

import java.io.*;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.*;

import net.siit.ling.Annotation;
import net.siit.text.TextUtil;

/**
 *
 * @author art
 */
public class TagWorker {
    final public static String OPT_EXTRACT  = "extract";
    final public static String OPT_ANNOTATE = "annotate";
    final public static String DEFAULT_LIST_PATH = "resources";
    final public static String DEFAULT_CHARSET = "utf-8";

    private String listPath = DEFAULT_LIST_PATH;
    private String charset  = DEFAULT_CHARSET;

    /**
     * Creates a new instance of TagWorker
     *
     * @param listPath
     * @param charset
     */
    public TagWorker(String listPath, String charset) {
        this.listPath = listPath;
        this.charset  = charset;
    }

    public String getListPath() {
        return listPath;
    }

    public void setListPath(String listPath) {
        this.listPath = listPath;
    }

    public String getCharset() {
        return charset;
    }

    public void setCharset(String charset) {
        this.charset = charset;
    }

    private String getFilename(String name) {
        return listPath + java.io.File.separator + name + ".txt";
    }

    private List<String> getList(String listName) {
        List<String> list = null;
        try {
            list = TextUtil.toList(new FileInputStream(getFilename(listName)), charset);
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        }
        return list;
    }

    /**
     *
     * @param listName
     * @return
     */
    private Map<String,Long> getCountedList(String listName) {
        Map<String,Long> list = null;
        FileInputStream fis;
        try {
            fis = new FileInputStream(getFilename(listName));
        } catch (FileNotFoundException ex1) {
            System.err.println("File not found, will created one: " + getFilename(listName));
            return new TreeMap<String,Long>(); // return empty list if file not found
        }

        try {
            list = toCountedList(fis, charset);
        } catch (NumberFormatException ex2) {
            ex2.printStackTrace();
        }
        return list;
    }

    /**
     *
     * @param input
     * @param charset
     * @return
     * @throws java.lang.NumberFormatException
     */
    private static Map<String,Long> toCountedList(InputStream input, String charset) throws NumberFormatException {
        Map<String,Long> list = new TreeMap<String,Long>();
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(input, charset));
            String str;
            while ((str = reader.readLine()) != null) {
                str = str.trim();
                if (str.length() > 0) {
                    String[] s = str.split("\\s", 2);
                    Long count;
                    try {
                        count = Long.parseLong(s[0]);
                    } catch(NumberFormatException ex) {
                        throw ex;
                    }
                    list.put(s[1], count);
                }
            }
            if (reader != null)
                reader.close();
        } catch (UnsupportedEncodingException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        return list;
    }

    private static void extractMarkedWords(String text, Map<String,Long> nouns, Map<String,Long> verbs, Map<String,Long> connectives, Map<String,Long> others) {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new StringReader(text));
        } catch (Exception e) {
            System.err.println(e.toString());
        } finally {
            if (reader == null)
                return; //System.exit(1);
        }

        try {
            String str;
            while ((str = reader.readLine()) != null) {
                str = str.trim();
                //if (str.length() < 1 || str.charAt(0) != '#') {
                /*
                if (str.length() < 1) {
                    System.err.println("Annotation syntax error.");
                    System.exit(3);
                } else {
                    str = str.substring(1);
                }
                 */

                StringBuffer l = new StringBuffer(3);
                StringBuffer w = new StringBuffer();
                char[] chars = str.toCharArray();
                int len = chars.length;
                int i = 0;
                while (i < len) {
                    if (chars[i] == '[') {
                        i++;
                        while ((i < len) && (!Character.isWhitespace(chars[i]))) {
                            l.append(chars[i]);
                            i++;
                        }
                        while ((i < len) && (Character.isWhitespace(chars[i]))) {
                            i++;
                        }
                        while ((i < len) && (chars[i] != ']')) {
                            w.append(chars[i]);
                            i++;
                        }
                        if ((l.length() > 0) && (w.length() > 0)) {
                            String label = l.toString();
                            String word  = w.toString();

                            //System.err.println(label + " : " + word);
                            if (label.equalsIgnoreCase(Annotation.CONNECTIVE)) {
                                Long count = connectives.get(word);
                                if (count == null) {
                                    count = new Long(1);
                                } else {
                                    count++;
                                }
                                connectives.put(word, count);
                            }
                            else if (label.equalsIgnoreCase(Annotation.SUBJECT) || label.equalsIgnoreCase(Annotation.OBJECT)) {
                                Long count = nouns.get(word);
                                if (count == null) {
                                    count = new Long(1);
                                } else {
                                    count++;
                                }
                                nouns.put(word, count);
                            }
                            else if (label.equalsIgnoreCase(Annotation.VERB)) {
                                Long count = verbs.get(word);
                                if (count == null) {
                                    count = new Long(1);
                                } else {
                                    count++;
                                }
                                verbs.put(word, count);
                            }
                            else {
                                Long count = others.get(word);
                                if (count == null) {
                                    count = new Long(1);
                                } else {
                                    count++;
                                }
                                others.put(word, count);
                            }
                        }
                        l.delete(0, l.length());
                        w.delete(0, w.length());
                    } else {
                        i++;
                    }
                }
            }
            reader.close();
        } catch (Exception e) {
            System.err.println(e.toString());
            //System.exit(2);
        }
    }

    private static String countedListToString(Map<String,Long> list) {
        StringBuffer text = new StringBuffer();
        Set<Entry<String,Long>> set = list.entrySet();

        @SuppressWarnings("unchecked")
        Entry<String,Long>[] a = new Entry[1];
        a = set.toArray(a);
        Arrays.sort(a, 0, a.length, new Comparator<Entry<String,Long>>() {
            public int compare(Entry<String, Long> a, Entry<String, Long> b) {
                return (int) (b.getValue() - a.getValue());
            }
        });

        for (Entry<String,Long> e : a) {
            text.append(e.getValue());
            text.append(' ');
            text.append(e.getKey());
            text.append('\n');
        }

        return text.toString();
    }

    /**
     * Read inFilename, extract words, and store them in coresponded files.
     *
     * @param inFilename
     * @param charset
     */
    public void extract(String inFilename, String charset) {
        System.err.println("== START: " + inFilename + " ==========");
        String text = null;
        text = TextUtil.load(inFilename, charset);
        if (text == null)
            System.exit(2);

        Map<String,Long> connectives  = getCountedList("connectives");
        Map<String,Long> nouns        = getCountedList("nouns");
        Map<String,Long> verbs        = getCountedList("verbs");
        Map<String,Long> others       = getCountedList("others");

        extractMarkedWords(text, nouns, verbs, connectives, others);

        String cs = countedListToString(connectives);
        String ns = countedListToString(nouns);
        String vs = countedListToString(verbs);
        String os = countedListToString(others);

        TextUtil.save(cs, getFilename("connectives"), charset);
        TextUtil.save(ns, getFilename("nouns"), charset);
        TextUtil.save(vs, getFilename("verbs"), charset);
        TextUtil.save(os, getFilename("others"), charset);

        /*
        System.out.println("-- Connectives -----------------");
        System.out.println(cs);
        System.out.println("-- Nouns -----------------------");
        System.out.println(ns);
        System.out.println("-- Verbs -----------------------");
        System.out.println(vs);
        System.out.println("-- Others ----------------------");
        System.out.println(os);
        System.out.println("== END: " + input + " ==========\n\n");
         */
    }

    /**
     *
     * @param inFilename
     */
    public void extract(String inFilename) {
        extract(inFilename, charset);
    }

    /**
     * @param inFilename input filename
     * @param outFilename input filename
     * @param charset
     */
    public void annotate(String inFilename, String outFilename, String charset) {
        String text = null;
        text = TextUtil.load(inFilename, charset);
        if (text == null)
            System.exit(2);

        List<String> connectives  = getList("connectives");
        //List<String> nouns        = getList("nouns");
        List<String> verbs        = getList("verbs");
        //List<String> others       = getList("others");

        // mark connectives, verbs
        text = TextUtil.mark(text, TextUtil.matchWords(text, connectives), "\n["+Annotation.CONNECTIVE+" ", "]\n");
        text = TextUtil.mark(text, TextUtil.matchWords(text, verbs), "["+Annotation.VERB+" ", "]");

        TextUtil.save(text, outFilename, charset);
    }

    /**
     *
     * @param inFilename
     * @param outFilename
     */
    public void annotate(String inFilename, String outFilename) {
        annotate(inFilename, outFilename, charset);
    }

    /**
     * Get the usage of the main method
     * 
     * @return
     */
    public static String getUsage() {
        return "usage: TagWorker mode charset resources__path <parameters>\n" +
               "* mode - can be 'extract' or 'annotate' \n" +
               "* charset - character set (encoding) e.g. 'utf-8', 'tis-620'\n" +
               "* extract - needs input_file as parameter\n" +
               "* annotate - needs input_file output_file as parameters\n";
    }
    
    /**
     * 
     * @param args
     */
    public static void main(String[] args) {
        if (args.length < 3) {
            System.err.print(getUsage());                    
            System.exit(1);
        }

        String mode = args[0];  // "extract" or "annotate"

        // args[1] = path to word list files
        TagWorker worker = new TagWorker(args[2], args[1]);

        if (mode.equalsIgnoreCase(OPT_EXTRACT)) {
            if (args.length < 4) {
                System.err.println("usage: TagWorker extract charset resources_path input_file");
                System.err.println("* charset is character set (encoding) e.g. 'utf-8', 'tis-620'");
                System.exit(1);
            }
            worker.extract(args[3]);
        } else
        if (mode.equalsIgnoreCase(OPT_ANNOTATE)) {
            if (args.length < 5) {
                System.err.println("usage: TagWorker annotate charset resource_path input_file output_file");
                System.err.println("* charset is character set (encoding) e.g. 'utf-8', 'tis-620'");
                System.exit(1);
            }
            worker.annotate(args[3], args[4]);
        }
    }

}
